<template>
  <Upload
        :file-list="fileList"
        :before-upload="beforeUpload"
        :on-change="handleChange"
        :multiple="multiple"
        :custom-request="customRequest"
        :showUploadList="false"
      >
    <Button type="primary" :loading="isUploading">
     上传文件
    </Button>
  </Upload>
</template>

<script setup lang="ts">
import { ref, defineProps, defineEmits } from 'vue';
import {Button,Upload, type UploadFile, type UploadProps,
} from 'ant-design-vue'
const props = withDefaults(defineProps<{
  fileList: UploadFile[];
  multiple?: boolean;
}>(), {
  fileList: () => []
});

// 添加loading状态
const isUploading = ref(false);

const emits = defineEmits<{
  (e: 'update:fileList', value: UploadFile[]): void;
  (e: 'uploadSuccess', files: UploadFile[]): void;
}>();

import jsSHA from 'jssha';
import { uuid } from '#/utils';
import { getUserBaseApi, QiniuCallback } from '#/api';
import { message } from 'ant-design-vue';

const beforeUpload: UploadProps['beforeUpload'] = (file) => {
  return true;
};

async function getFileSha1(file: File): Promise<string> {
  const shaObj = new jsSHA('SHA-1', 'ARRAYBUFFER');
  shaObj.update(await file.arrayBuffer());
  return shaObj.getHash('HEX');
}

function getSaveName(file: File, sha1: string, savenameTemplate: string): string {
  const fileSuffix = file.name.split('.').pop()?.toLowerCase() || '';
  const fileName = file.name.slice(0, Math.max(0, file.name.lastIndexOf('.') || file.name.length));
  const dateObj = new Date();

  const replaceArr: Record<string, string> = {
    '{topic}': 'default',
    '{year}': dateObj.getFullYear().toString(),
    '{mon}': `0${dateObj.getMonth() + 1}`.slice(-2),
    '{day}': dateObj.getDate().toString(),
    '{hour}': dateObj.getHours().toString(),
    '{min}': dateObj.getMinutes().toString(),
    '{sec}': dateObj.getSeconds().toString(),
    '{random}': uuid(),
    '{random32}': Math.random().toString(36).slice(2, 10),
    '{filename}': fileName.slice(0, 100),
    '{suffix}': fileSuffix,
    '{.suffix}': `.${fileSuffix}`,
    '{filesha1}': sha1,
  };

  const replaceKeys = Object.keys(replaceArr).join('|');
  const savename = savenameTemplate[0] == '/' ? savenameTemplate.slice(1) : savenameTemplate;

  return savename.replaceAll(new RegExp(replaceKeys, 'gm'), (match) => {
    return replaceArr[match] || match;
  });
}

interface UploadConfig {
  maxsize: number;
  savename: string;
  mimetype: string;
  url: string;
  token: string;
  mode: string;
}

const getUploadConfig = async (): Promise<UploadConfig> => {
  try {
    const { siteConfig } = await getUserBaseApi();
    if (!siteConfig?.upload) {
      throw new Error('未获取到上传配置');
    }
    return siteConfig.upload;
  } catch (error) {
    console.error('获取上传配置失败:', error);
    throw error;
  }
}

const customRequest: UploadProps['customRequest'] = async ({ file, onError, onProgress, onSuccess }) => {
  try {
    // 如果是第一个开始上传的文件，设置loading状态
    if ((props.fileList || []).every(f => f.status !== 'uploading')) {
      isUploading.value = true;
    }

    onProgress?.({ percent: 0 });
    const uploadConfig = await getUploadConfig();

    // 文件类型和大小校验
    const allowedTypes = uploadConfig.mimetype.split(',');
    const fileExtension = file.name.split('.').pop()?.toLowerCase() || '';
    if (!allowedTypes.includes(fileExtension)) {
      throw new Error(`不支持的文件类型，仅支持${uploadConfig.mimetype}`);
    }

    if (file.size > uploadConfig.maxsize) {
      throw new Error(`文件大小不能超过${(uploadConfig.maxsize / 1024 / 1024).toFixed(2)}MB`);
    }

    onProgress?.({ percent: 10 });
    message.loading('正在处理文件...');
    const sha1 = await getFileSha1(file);
    const fileKey = getSaveName(file, sha1, uploadConfig.savename);

    const formData = new FormData();
    formData.append('file', file);
    formData.append('token', uploadConfig.token);
    formData.append('key', fileKey);

    const fileUuid = uuid();
    const xhr = new XMLHttpRequest();

    xhr.upload.addEventListener('progress', (e) => {
      if (e.total > 0) {
        const percent = Math.round((e.loaded / e.total) * 100);
        onProgress?.({ percent });
      }
    });

    xhr.addEventListener('load', async () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        try {
          const response = JSON.parse(xhr.responseText);
          await QiniuCallback({
            url: response.key,
            sha1,
            name: file.name,
            size: file.size,
            type: file.type,
          });
          onSuccess?.(response, file);
        } catch {
          onError?.(new Error('上传成功但解析响应失败'));
        }
      } else {
        onError?.(new Error(`上传失败: ${xhr.statusText}`));
      }
    });

    xhr.addEventListener('error', () => onError?.(new Error('上传过程中发生错误')));

    const urlWithParams = new URL(uploadConfig.url);
    urlWithParams.searchParams.append('uuid', fileUuid);
    xhr.open('POST', urlWithParams.toString());
    xhr.send(formData);
    message.destroy();
  } catch (error) {
    message.destroy();
    message.error(error instanceof Error ? error.message : '上传失败');
    onError?.(error instanceof Error ? error : new Error(String(error)));
    // 发生错误时也关闭loading
    isUploading.value = false;
  }
};

const handleChange: UploadProps['onChange'] = async (info) => {
  const { fileList: newFileList } = info;
  const updatedFileList = await Promise.all(
    newFileList.map(async (file) => {
      if (file.status === 'done' && file.response && file.response.key && !file.url) {
        try {
          const { siteConfig } = await getUserBaseApi();
          return { ...file, url: `${siteConfig.apiUrl}${file.response.key}` };
        } catch (error) {
          console.error('构建预览URL失败:', error);
        }
      }
      return file;
    })
  );
  emits('update:fileList', updatedFileList);

  // 检查是否有文件正在上传
  const hasUploadingFiles = updatedFileList.some(file => file.status === 'uploading');

  // 如果没有文件正在上传，则关闭loading
  if (!hasUploadingFiles) {
    isUploading.value = false;
  }

  // 所有文件处理完成后触发上传成功事件
  // 确保所有文件都处于'done'状态才触发成功事件
  const allFilesProcessed = updatedFileList.every(file => file.status === 'done');
  if (allFilesProcessed) {
    emits('uploadSuccess', updatedFileList);
    isUploading.value = false; // 确保loading状态被关闭
  }
};

// 暴露组件供外部使用
defineExpose({
  customRequest
});
</script>
